package com.dlc.shop.security.common.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.dto.AppConnectDTO;
import com.dlc.shop.bean.event.LevelUpEvent;
import com.dlc.shop.bean.event.UserRegisterLogEvent;
import com.dlc.shop.bean.event.allinpay.CreateAllinpayMemberEvent;
import com.dlc.shop.bean.model.User;
import com.dlc.shop.bean.model.UserExtension;
import com.dlc.shop.bean.param.UserExcelParam;
import com.dlc.shop.bean.param.UserRegisterExcelParam;
import com.dlc.shop.common.allinpay.constant.PaySysType;
import com.dlc.shop.common.bean.PaySettlementConfig;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.enums.StatusEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.common.util.BeanUtil;
import com.dlc.shop.common.util.DataBatchHandleUtil;
import com.dlc.shop.common.util.IpHelper;
import com.dlc.shop.common.util.PasswordUtil;
import com.dlc.shop.dao.UserExtensionMapper;
import com.dlc.shop.dao.UserMapper;
import com.dlc.shop.security.common.dao.AppConnectMapper;
import com.dlc.shop.security.common.manager.PasswordManager;
import com.dlc.shop.security.common.model.AppConnect;
import com.dlc.shop.security.common.service.AppConnectService;
import com.dlc.shop.service.SysConfigService;
import com.dlc.shop.service.UserExtensionService;
import com.dlc.shop.service.UserService;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 *
 * @author lgh on 2018/09/07.
 */
@Service
@AllArgsConstructor
public class AppConnectServiceImpl extends ServiceImpl<AppConnectMapper, AppConnect> implements AppConnectService {

    private final AppConnectMapper appConnectMapper;
    private final ApplicationContext applicationContext;
    private final UserMapper userMapper;
    private final UserService userService;
    private final UserExtensionMapper userExtensionMapper;
    private final UserExtensionService userExtensionService;
    private final PasswordEncoder passwordEncoder;
    private final PasswordManager passwordManager;
    private final SysConfigService sysConfigService;

    /**
     * YamiUserServiceImpl#insertUserIfNecessary 将会清除该缓存信息
     */
    @Override
    public AppConnect getByBizUserId(String bizUserId, Integer appId) {
        return appConnectMapper.getByBizUserId(bizUserId, appId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User registerAndBindUser(String mobile, String password, String tempUid) {
        // 新建用户
        User user = new User();
        user.setModifyTime(new Date());
        user.setUserRegtime(new Date());
        user.setUserRegip(IpHelper.getIpAddr());
        user.setStatus(1);
        user.setUserMobile(mobile);
        if (StrUtil.isNotBlank(password)) {
            String decryptPassword = passwordManager.decryptPassword(password);
            PasswordUtil.check(decryptPassword);
            user.setLoginPassword(passwordEncoder.encode(decryptPassword));
        }
        // 昵称默认位u + 手机尾号后4位
        user.setNickName("u" + mobile.substring(7));
        String userId = IdUtil.simpleUUID();
        user.setUserId(userId);
        user.setLevel(1);
        user.setLevelType(0);
        // 默认开启商品个性化推荐
        user.setProdRecommendation(1);
        userMapper.insert(user);
        long registerUserNum = userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, mobile).between(User::getStatus, StatusEnum.DISABLE.value(), StatusEnum.ENABLE.value()));
        if (registerUserNum > 1) {
            throw new YamiShopBindException("yami.user.phone.exist");
        }
        // 创建用户拓展信息
        UserExtension userExtension = new UserExtension();
        userExtension.setBalance(0.0);
        userExtension.setTotalBalance(0.0);
        userExtension.setGrowth(0);
        userExtension.setLevel(1);
        userExtension.setLevelType(0);
        userExtension.setScore(0L);
        userExtension.setUpdateTime(new Date());
        userExtension.setVersion(0);
        userExtension.setSignDay(0);
        userExtension.setUserId(userId);
        userExtension.setAllinpayBalance(0.0);
        userExtension.setAllinpayTotalBalance(0.0);
        userExtension.setAllinpayCreate(0);
        userExtension.setAllinpayRealNameSet(0);
        userExtension.setAllinpayPhoneBind(0);
        userExtension.setAllinpayProtocolSign(0);
        userExtension.setAllinpayPayPwdSet(0);
        userExtension.setAllinpayPayAcctBind(0);
        userExtensionMapper.insert(userExtension);
        //用户注册成功后发送等级提升事件
        applicationContext.publishEvent(new LevelUpEvent(userExtension,1,0, Constant.PLATFORM_SHOP_ID, 1));
        if (StrUtil.isNotBlank(tempUid)) {
            appConnectMapper.bindUserIdByTempUid(user.getUserId(), tempUid);
        }
        // 若开启通联，则同步创建通联个人会员
        PaySettlementConfig paySettlementConfig = sysConfigService.getSysConfigObject(Constant.PAY_SETTLEMENT_CONFIG, PaySettlementConfig.class);
        if (Objects.equals(paySettlementConfig.getPaySettlementType(), PaySysType.ALLINPAY.value())) {
            CreateAllinpayMemberEvent event = new CreateAllinpayMemberEvent();
            event.setUserIds(Collections.singletonList(user.getUserId()));
            if (StrUtil.isNotBlank(tempUid)) {
                AppConnect appConnect = appConnectMapper.getByTempUid(tempUid);
                AppConnectDTO appConnectDTO = new AppConnectDTO(appConnect.getUserId(), appConnect.getAppId(), appConnect.getTempUid());
                event.setAppConnects(Collections.singletonList(appConnectDTO));
            }
            applicationContext.publishEvent(event);
        }
        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer batchRegisterUser(UserExcelParam params, List<UserRegisterExcelParam> userList, Set<String> repeatPhoneSet, Set<String> repeatMailSet, Set<String> passwordSet) {
        // 成功注册用户条数
        int registerNum = 0;
        if (CollectionUtils.isEmpty(userList)) {
            return registerNum;
        }
        List<String> phones = userList.stream().map(UserRegisterExcelParam::getPhone).filter(Objects::nonNull).collect(Collectors.toList());
        List<String> mails = userList.stream().map(UserRegisterExcelParam::getUserMail).filter(Objects::nonNull).collect(Collectors.toList());
        // 查询已经存在的手机号用户
        List<User> users = userMapper.listByUserPhones(phones);
        // 查询已经存在的邮箱用户
        List<User> userListByMail;
        if (CollUtil.isNotEmpty(mails)) {
            userListByMail =userMapper.listByUserMails(mails);
        } else {
            userListByMail = Collections.emptyList();
        }
        if (CollectionUtils.isNotEmpty(users)) {
            List<String> mobiles = users.stream().map(User::getUserMobile).toList();
            userList = userList.stream().filter(item -> !mobiles.contains(item.getPhone())).collect(Collectors.toList());
            repeatPhoneSet.addAll(mobiles);
        }
        if (CollectionUtils.isNotEmpty(userListByMail) && CollectionUtils.isNotEmpty(userList)) {
            List<String> userMails = userListByMail.stream().map(User::getUserMail).toList();
            userList = userList.stream().filter(item -> !userMails.contains(item.getUserMail())).collect(Collectors.toList());
            repeatMailSet.addAll(userMails);
        }
        // 判断用户密码格式
        if (CollectionUtils.isNotEmpty(userList)) {
            userList = userList.stream().filter(item -> {
                boolean success = PasswordUtil.checkFormat(item.getPassword());
                if (!success) {
                    passwordSet.add(item.getPassword());
                }
                return success;
            }).collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(userList)) {
            return registerNum;
        }
        registerNum = userList.size();
        // 用户
        List<User> userSave = new ArrayList<>();
        // 用户扩展表
        List<UserExtension> userExtensionsSave = new ArrayList<>();
        // 处理用户和拓展表数据
        registerNum = handleUserExtension(userList, params, registerNum, userSave, userExtensionsSave);

        // 大数据批量处理
        // 插入用户数据
        DataBatchHandleUtil.batchSplitInsert(userSave, userService::saveBatch);

        //用户注册成功后发送日志事件 积分log 成长值log
        applicationContext.publishEvent(new UserRegisterLogEvent(userExtensionsSave));

        // 插入用户扩展数据 - 等级处理完成后再一次性插入
        DataBatchHandleUtil.batchSplitInsert(userExtensionsSave, userExtensionService::saveBatch);

        // 若开启通联，则同步创建通联个人会员
        PaySettlementConfig paySettlementConfig = sysConfigService.getSysConfigObject(Constant.PAY_SETTLEMENT_CONFIG, PaySettlementConfig.class);
        if (Objects.equals(paySettlementConfig.getPaySettlementType(), PaySysType.ALLINPAY.value())) {
            CreateAllinpayMemberEvent event = new CreateAllinpayMemberEvent();
            event.setUserIds(userSave.stream().map(User::getUserId).collect(Collectors.toList()));
            applicationContext.publishEvent(event);
        }
        return registerNum;
    }




    private int handleUserExtension(List<UserRegisterExcelParam> userList, UserExcelParam params, int registerNum, List<User> userSave, List<UserExtension> userExtensionsSave) {
        Date now = new Date();
        int i = 0;
        // 批量导入的密码一般都大量重复
        Map<String, String> passwordMap = new HashMap<>(Constant.INITIAL_CAPACITY);
        for (UserRegisterExcelParam param : userList) {
            System.out.println(i++);
            // 用户
            String userId = IdUtil.simpleUUID();
            if(param.getBalance() > UserRegisterExcelParam.MAX_BALANCE){
                //余额超出最大范围，最多不得超过999999999.99
                params.getErrorRowInfos().add(I18nMessage.getMessage("yami.balance.out.error"));
                params.setSuccessNum(params.getSuccessNum() -1);
                params.setErrorNum(params.getErrorNum() + 1);
                registerNum--;
                continue;
            }
            if(param.getScore() > UserRegisterExcelParam.MAX_SCORE){
                //积分超出最大范围，最多不得超过100000000
                params.getErrorRowInfos().add(I18nMessage.getMessage("yami.score.out.error"));
                params.setSuccessNum(params.getSuccessNum() - 1);
                params.setErrorNum(params.getErrorNum() + 1);
                registerNum--;
                continue;
            }
            User user = BeanUtil.map(param, User.class);
            user.setUserId(userId);
            user.setUserMobile(param.getPhone());
            if (!passwordMap.containsKey(param.getPassword())) {
                String encode = passwordEncoder.encode(param.getPassword());
                passwordMap.put(param.getPassword(), encode);
                user.setLoginPassword(encode);
            } else {
                user.setLoginPassword(passwordMap.get(param.getPassword()));
            }
            user.setUserName(param.getPhone());
            user.setModifyTime(now);
            user.setUserRegtime(now);
            user.setStatus(1);
            // 默认开启商品个性化推荐
            user.setProdRecommendation(1);
            userSave.add(user);
            // 用户扩展信息
            UserExtension userExtension = new UserExtension();
            userExtension.setUserId(userId);
            userExtension.setLevel(user.getLevel());
            userExtension.setLevelType(user.getLevelType());
            userExtension.setGrowth(param.getGrowth());
            userExtension.setScore(param.getScore());
            userExtension.setBalance(param.getBalance());
            userExtension.setTotalBalance(param.getBalance());
            userExtension.setAllinpayBalance(0.0);
            userExtension.setAllinpayTotalBalance(0.0);
            userExtension.setAllinpayCreate(0);
            userExtension.setAllinpayRealNameSet(0);
            userExtension.setAllinpayPhoneBind(0);
            userExtension.setAllinpayProtocolSign(0);
            userExtension.setAllinpayPayPwdSet(0);
            userExtension.setAllinpayPayAcctBind(0);
            userExtension.setVersion(0);
            userExtension.setUpdateTime(now);
            userExtension.setUserMobile(user.getUserMobile());
            userExtensionsSave.add(userExtension);
        }
        return registerNum;
    }

    @Override
    public AppConnect getByTempUid(String tempUid) {
        return appConnectMapper.getByTempUid(tempUid);
    }

    @Override
    public void unBindUser(String bizUserId, Integer socialType) {
        appConnectMapper.unBindUser(bizUserId, socialType);
    }

}
